#include "../../gui_al.h"
#include "gui_al.h"
#include "edit.h"
#include "../../error.h"

int _mood_state = -1;
int _weather_state = -1;

struct edit_gui_al_tag {
	GtkTextTag *tag;
	struct edit_gui_al_tag *next;
};

struct edit_gui_al_tag *_headTag;


int _focus = 0;
int _lnk_indx = 0;





static void remove_tag(GtkTextTag * tag, gpointer data)
{				//This function creates a stack of tag references.
	//For some reason, you can't remove links within a foreach.

	char *name = NULL;
	g_object_get((gpointer *) tag, "name", (gchar **) & name, NULL);
	if (name != NULL) {
		free(name);
		struct edit_gui_al_tag *nue = malloc(sizeof *nue);
		nue->tag = tag;
		if (_headTag != NULL)
			nue->next = _headTag;
		else
			nue->next = NULL;
		_headTag = nue;
	}
}


static void remove_mark(GtkTextTag * tag, gpointer data)
{				//This function creates a stack of tag references.
	//For some reason, you can't remove links within a foreach.
	char *name = NULL;
	g_object_get((gpointer *) tag, "name", (gchar **) & name, NULL);
	if (name == NULL) {
		struct edit_gui_al_tag *nue = malloc(sizeof *nue);
		nue->tag = tag;
		if (_headTag != NULL)
			nue->next = _headTag;
		else
			nue->next = NULL;
		_headTag = nue;
	}
}


int combo_box_text(int str, GtkWidget * widget)
{

	if (str <= -1) {
		int ret = gtk_combo_box_get_active(GTK_COMBO_BOX(widget));
		return ret;
	}

	gtk_combo_box_set_active(GTK_COMBO_BOX(widget), str);


	return -1;
	/* Instructional: how to search a combo box by char*
	   GtkTreeModel *tree = gtk_combo_box_get_model(GTK_COMBO_BOX(widget));
	   GtkTreeIter i;
	   if (gtk_tree_model_get_iter_first(tree, &i) == FALSE)
	   return NULL;
	   int c=0;
	   do
	   {
	   enum
	   {
	   COL_ONLY
	   };
	   gchar *txt;
	   gtk_tree_model_get(tree, &i, COL_ONLY, &txt);
	   if (strcmp((char *)txt, str) == 0)
	   gtk_combo_box_set_active(widget, c);
	   ++c;
	   } while (gtk_tree_model_iter_next(tree, &i) != FALSE);
	   return NULL; */
}


int edit_gui_al_weather(int weather)
{
	return combo_box_text(weather, _weather);
}
int edit_gui_al_mood(int mood)
{
	return combo_box_text(mood, _mood);
}

char *edit_gui_al_title(char *title)
{

	char *tmp = NULL;
	if (title == NULL) {
		char *t = (char *)gtk_entry_get_text(GTK_ENTRY(_subject));
		if (g_utf8_validate(t, 3, NULL) == TRUE) {
			elog_sp_cat(&tmp, t, NULL);
			return tmp;
		}
		return NULL;
	}
	if (title[0]) {
		if (g_utf8_validate(title, 3, NULL) )
			gtk_entry_set_text(GTK_ENTRY(_subject), (gchar *) title);
		else
			elog_wrn_print("Error setting your subject line");
	}
	else
		gtk_entry_set_text(GTK_ENTRY(_subject), (gchar *) title);

	return NULL;
}

char *edit_gui_al_creationDate(char *date)
{

	if (date == NULL) {
		char *x;
		elog_sp_cat(&x, (char *)
			    gtk_label_get_text(GTK_LABEL(_creationDate)),
			    NULL);
		return x;
	}
	//gtk_label_set_text(GTK_LABEL(_creationDate), date);
	char *markup;
	markup =
	    g_markup_printf_escaped
	    ("<span size=\"larger\" underline=\"single\"><b><i>%s</i></b></span>",
	     date);
	gtk_label_set_markup(GTK_LABEL(_creationDate), markup);
	free(markup);

	return NULL;
}

char *edit_gui_al_text(char *txt)
{


	GtkTextBuffer *buffer =
	    gtk_text_view_get_buffer(GTK_TEXT_VIEW(_textBox));



	if (txt == NULL) {
		GtkTextIter start, end;
		gtk_text_buffer_get_start_iter(buffer, &start);
		gtk_text_buffer_get_end_iter(buffer, &end);
		char *ret =
		    (char *) gtk_text_buffer_get_text(buffer, &start, &end,
						      TRUE);
		return ret;
	}
	//GtkTextTagTable *nueTable = gtk_text_tag_table_new();
	//GtkTextBuffer *nueBuffer = gtk_text_buffer_new(nueTable);

	//for some reason, gtk handles all the freeing of the buffer, tag_table, and
	//the texttags, so, we don't have to worry about it!  

	//It may seem really inefficient to make a new buffer and tag table
	//But it's a LOT easier than the alternatives for getting rid off
	//the old text tags.

	GtkTextIter st, nd;
	gtk_text_buffer_get_iter_at_offset(buffer, &st, 0);
	gtk_text_buffer_get_end_iter(buffer, &nd);
	gtk_text_buffer_remove_all_tags(buffer, &st, &nd);


	edit_gui_al_clearLinks();



	gtk_text_buffer_set_text(buffer, txt, strlen(txt));

	return NULL;
}

void edit_gui_al_clearLinks()
{
	GtkTextBuffer *buffer =
	    gtk_text_view_get_buffer(GTK_TEXT_VIEW(_textBox));
	GtkTextTagTable *table = gtk_text_buffer_get_tag_table(buffer);
	_headTag = NULL;
	gtk_text_tag_table_foreach(table, remove_tag, NULL);
	while (_headTag != NULL)	//going through the stack.
	{
		struct edit_gui_al_tag *p = _headTag;
		_headTag = p->next;
		gtk_text_tag_table_remove(table, p->tag);
		free(p);
	}
}

void edit_gui_al_removeLink(const char *name)
{

	GtkTextBuffer *buffer =
	    gtk_text_view_get_buffer(GTK_TEXT_VIEW(_textBox));
	GtkTextTagTable *table = gtk_text_buffer_get_tag_table(buffer);
	GtkTextTag *tag = gtk_text_tag_table_lookup(table, name);
	gtk_text_tag_table_remove(table, tag);	//should destroy it.

}
void edit_gui_al_removeChar(int loc)
{
	edit_gui_al_removeStr(loc, 1);
}
void edit_gui_al_insertChar(int loc, unsigned int character)
{
	elog_tab_edit_ignore_signals(1);
	GtkTextBuffer *buffer =
	    gtk_text_view_get_buffer(GTK_TEXT_VIEW(_textBox));
	GtkTextIter iter;
	gtk_text_buffer_get_iter_at_offset(buffer, &iter, (gint) loc);
	gchar x[6];
	int n = g_unichar_to_utf8(character, x);

	gtk_text_buffer_insert_interactive(buffer, &iter, (gchar *) x, n,
					   TRUE);
	elog_tab_edit_ignore_signals(0);
}
void edit_gui_al_removeStr(int loc, int len)
{
	elog_tab_edit_ignore_signals(1);
	GtkTextBuffer *buffer =
	    gtk_text_view_get_buffer(GTK_TEXT_VIEW(_textBox));
	GtkTextIter iter, iter_end;
	gtk_text_buffer_get_iter_at_offset(buffer, &iter, (gint) loc);
	gtk_text_buffer_get_iter_at_offset(buffer, &iter_end,
					   (gint) loc + len);
	gtk_text_buffer_delete_interactive(buffer, &iter, &iter_end, TRUE);
	elog_tab_edit_ignore_signals(0);
}

int edit_gui_al_cursor(int n)
{
	if (n < 0) {
		GtkTextBuffer *buffer =
		    gtk_text_view_get_buffer(GTK_TEXT_VIEW(_textBox));
		GtkTextIter iter;
		GtkTextMark *mark =
		    gtk_text_buffer_get_mark(buffer, "insert");
		gtk_text_buffer_get_iter_at_mark(buffer, &iter, mark);
		return gtk_text_iter_get_offset(&iter);
	}
	return -1;
}
void edit_gui_al_insertStr(int loc, char *str)
{
	elog_tab_edit_ignore_signals(1);

	GtkTextBuffer *buffer =
	    gtk_text_view_get_buffer(GTK_TEXT_VIEW(_textBox));
	GtkTextIter iter;
	if (loc == -1) {
		GtkTextMark *mark =
		    gtk_text_buffer_get_mark(buffer, "insert");
		gtk_text_buffer_get_iter_at_mark(buffer, &iter, mark);
	} else
		gtk_text_buffer_get_iter_at_offset(buffer, &iter,
						   (gint) loc);
	gtk_text_buffer_insert_interactive(buffer, &iter, (gchar *) str,
					   -1, TRUE);
	elog_tab_edit_ignore_signals(0);
}

char *edit_gui_al_getSelectedText()
{
	GtkTextBuffer *buffer =
	    gtk_text_view_get_buffer(GTK_TEXT_VIEW(_mainTextView));
	GtkTextMark *sel1 =
	    gtk_text_buffer_get_mark(GTK_TEXT_BUFFER(buffer), "insert");
	GtkTextMark *sel2 =
	    gtk_text_buffer_get_mark(GTK_TEXT_BUFFER(buffer),
				     "selection_bound");
	GtkTextIter iter1;
	GtkTextIter iter2;
	gtk_text_buffer_get_iter_at_mark(GTK_TEXT_BUFFER(buffer), &iter1,
					 sel1);
	gtk_text_buffer_get_iter_at_mark(GTK_TEXT_BUFFER(buffer), &iter2,
					 sel2);
	return (char *) gtk_text_buffer_get_text(buffer, &iter1, &iter2,
						 TRUE);
}


int _gui_al_textCounter = 0;

int edit_gui_al_textLink(int start, int end, char *lnk)
{
	GtkTextBuffer *buffer =
	    gtk_text_view_get_buffer(GTK_TEXT_VIEW(_textBox));

	char *name = elog_sp_shortToString(_gui_al_textCounter);
	++_gui_al_textCounter;

	gtk_text_buffer_create_tag(buffer, (gchar *) name, "foreground",
				   "blue", "underline", TRUE, NULL);
	//Note to self:
	//When the manual says that they can't have the same name twice:  BLOODY LISTEN!
	//The above line had a name before, it was a hard bug to track....

	++_lnk_indx;

	GtkTextIter st, nd;
	gtk_text_buffer_get_iter_at_offset(buffer, &st, start);
	gtk_text_buffer_get_iter_at_offset(buffer, &nd, end);

	gtk_text_buffer_apply_tag_by_name(buffer, name, &st, &nd);
	free(name);

	return _gui_al_textCounter - 1;
}

void edit_gui_al_markText(const char *text, const char *start,
			  const char *end)
{
	int s, e;
	s = g_utf8_pointer_to_offset(text, start);
	e = g_utf8_pointer_to_offset(text, end);

	GtkTextBuffer *buffer =
	    gtk_text_view_get_buffer(GTK_TEXT_VIEW(_textBox));
	GtkTextTag *n =
	    gtk_text_buffer_create_tag(buffer, NULL, "foreground", "red",
				       "scale", PANGO_SCALE_X_LARGE, NULL);
	GtkTextIter st, nd;
	gtk_text_buffer_get_iter_at_offset(buffer, &st, s);
	gtk_text_buffer_get_iter_at_offset(buffer, &nd, e);
	gtk_text_buffer_apply_tag(buffer, n, &st, &nd);
}

void edit_gui_al_clearTextMarks()
{

	GtkTextBuffer *buffer =
	    gtk_text_view_get_buffer(GTK_TEXT_VIEW(_textBox));
	GtkTextTagTable *table = gtk_text_buffer_get_tag_table(buffer);
	gtk_text_tag_table_foreach(table, remove_mark, NULL);
	while (_headTag != NULL) {
		gtk_text_tag_table_remove(table, _headTag->tag);
		struct edit_gui_al_tag *p = _headTag->next;
		free(_headTag);
		_headTag = p;
	}

}

void edit_gui_al_setVisible(int yn)
{

	GtkTextBuffer *buffer =
	    gtk_text_view_get_buffer(GTK_TEXT_VIEW(_mainTextView));
	if (0 == yn) {
		if (GTK_WIDGET_HAS_FOCUS(_textBox))
			_focus = 1;
		else
			_focus = 0;
		gtk_text_buffer_begin_user_action(buffer);
		gtk_widget_hide(_textBox);
	} else {
		gtk_text_buffer_end_user_action(buffer);
		gtk_widget_show(_textBox);
		if (_focus)
			gtk_widget_grab_focus(_textBox);
	}

}
void edit_gui_al_jump_to(int pos)
{
	GtkTextBuffer *buffer =
	    gtk_text_view_get_buffer(GTK_TEXT_VIEW(_mainTextView));
	GtkTextIter iter;
	gtk_text_buffer_get_iter_at_offset(buffer, &iter, pos);
	gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(_mainTextView), &iter,
				     0.0, TRUE, 0, 0);
}



void edit_gui_al_setImage(int mood, int weather)
{
	if (mood == -1 || weather == -1)
		return;
	char *mood_c = elog_sp_shortToString(mood);
	char *weather_c = elog_sp_shortToString(weather);

	char *file_mood;
	elog_sp_cat(&file_mood, getenv("HOME"), "/.elog/default/Smilies/",
		    mood_c, ".png", NULL);
	char *file_weather;
	elog_sp_cat(&file_weather, getenv("HOME"),
		    "/.elog/default/Weather/", weather_c, ".png", NULL);


	GError *error = NULL;
	GdkPixbufLoader *loader = gdk_pixbuf_loader_new();

	int landscape = (mood + weather) / 2;

	if (elog_img_landscape(landscape) == NULL) {
		gdk_pixbuf_loader_close(loader, &error);
		return;
	}

	gdk_pixbuf_loader_write(loader, elog_img_landscape(landscape),
				elog_img_landscapeSize(landscape), &error);
	GdkPixbuf *landscape_pb = gdk_pixbuf_loader_get_pixbuf(loader);
	gdk_pixbuf_loader_close(loader, &error);

	loader = gdk_pixbuf_loader_new();
	gdk_pixbuf_loader_write(loader, elog_img_smiley(mood),
				elog_img_smileySize(mood), &error);
	GdkPixbuf *mood_pb = gdk_pixbuf_loader_get_pixbuf(loader);
	gdk_pixbuf_loader_close(loader, &error);


	loader = gdk_pixbuf_loader_new();
	gdk_pixbuf_loader_write(loader, elog_img_weather(weather),
				elog_img_weatherSize(weather), &error);
	GdkPixbuf *weather_pb = gdk_pixbuf_loader_get_pixbuf(loader);
	gdk_pixbuf_loader_close(loader, &error);


	int w = elog_gui_al_pane(-1);
	int h = 2.5 * w;

	int mood_n_channels = gdk_pixbuf_get_n_channels(mood_pb);
	int mood_rowstride = gdk_pixbuf_get_rowstride(mood_pb);


	int landscape_n_channels = gdk_pixbuf_get_n_channels(landscape_pb);
	int landscape_rowstride = gdk_pixbuf_get_rowstride(landscape_pb);

	int weather_n_channels = gdk_pixbuf_get_n_channels(weather_pb);
	int weather_rowstride = gdk_pixbuf_get_rowstride(weather_pb);
	int height = gdk_pixbuf_get_height(weather_pb);
	int width = gdk_pixbuf_get_width(weather_pb);

	guchar *pixels = gdk_pixbuf_get_pixels(weather_pb);


	guchar *smiley = gdk_pixbuf_get_pixels(mood_pb);

	guchar *bottom = gdk_pixbuf_get_pixels(landscape_pb);


	int y;
	for (y = 0; y < height; ++y) {
		int row;
		for (row = 0; row < width; ++row) {
			guchar *p =
			    pixels + y * weather_rowstride +
			    row * weather_n_channels;
			guchar *s =
			    smiley + y * mood_rowstride +
			    row * mood_n_channels;
			guchar *l =
			    bottom + y * landscape_rowstride +
			    row * landscape_n_channels;

			if (s[3] == 255) {
				p[0] = s[0];
				p[1] = s[1];
				p[2] = s[2];
			}	//no need to do divisions here
			else if (s[3] > 0) {	//blending alpha's                
				p[0] =
				    ((float) s[3] / 255.0) * (float) s[0] +
				    (255.0 - (float) s[3])
				    / 255.0 * (float) p[0];
				p[1] =
				    ((float) s[3] / 255.0) * (float) s[1] +
				    (255.0 - (float) s[3])
				    / 255.0 * (float) p[1];
				p[2] =
				    ((float) s[3] / 255.0) * (float) s[2] +
				    (255.0 - (float) s[3])
				    / 255.0 * (float) p[2];
			}

			if (l[3] == 255) {
				p[0] = l[0];
				p[1] = l[1];
				p[2] = l[2];
			}	//no need to do divisions here
			else if (l[3] > 0) {	//blending alpha's                
				p[0] =
				    ((float) l[3] / 255.0) * (float) l[0] +
				    (255.0 - (float) l[3])
				    / 255.0 * (float) p[0];
				p[1] =
				    ((float) l[3] / 255.0) * (float) l[1] +
				    (255.0 - (float) l[3])
				    / 255.0 * (float) p[1];
				p[2] =
				    ((float) l[3] / 255.0) * (float) l[2] +
				    (255.0 - (float) l[3])
				    / 255.0 * (float) p[2];
			}

		}
	}


	if (error != NULL) {
		elog_err_print_console(g_quark_to_string(error->domain));

		return;
	}


	if (h > 0) {
		GdkPixbuf *scaled =
		    gdk_pixbuf_scale_simple(weather_pb, w, h,
					    GDK_INTERP_HYPER);

		gtk_image_set_from_pixbuf(GTK_IMAGE(_sideImage), scaled);

		g_object_unref(scaled);
	} else
		gtk_image_set_from_pixbuf(GTK_IMAGE(_sideImage),
					  weather_pb);

	g_object_unref(mood_pb);
	g_object_unref(weather_pb);
	g_object_unref(landscape_pb);
	free(mood_c);
	free(weather_c);

}


char *edit_gui_al_lastEdit(const char *date)
{

	if (date == NULL) {
		char *x;
		elog_sp_cat(&x,
			    (char *) gtk_label_get_text(GTK_LABEL(_date)),
			    NULL);
		return x;
	}

	gtk_label_set_text(GTK_LABEL(_date), date);

	return NULL;
}
